<?php

/**
 * NOTICE OF LICENSE
 *
 * THIS SOURCE FILE IS PART OF EVEBIT'S PRIVATE PROJECT.
 * 
 * DO NOT USE THIS FILE IN OTHER PLACE.
 *
 * @category  Evebit
 * @package   App_Model
 * @author    Cheng Wei <berlios.o@gmail.com>
 * @version   $$Id: Abstract.php 130 2011-03-18 03:10:02Z cheng.wei $$
 * @copyright Copyright (c) 2008 Evebit Inc. China (http://www.evebit.com)
 */

/**
 * Abstract model
 * 
 * @package App_Model
 * @author  Cheng Wei <berlios.o@gmail.com>
 * @version $$Id: Abstract.php 130 2011-03-18 03:10:02Z cheng.wei $$
 */
abstract class Evebit_Model_Abstract extends Varien_Object {
	/**
	 * Prefix of model events names
	 *
	 * @var string
	 */
	protected $_eventPrefix = 'core_abstract';
	
	/**
	 * Parameter name in event
	 *
	 * In observe method you can use $observer->getEvent()->getObject() in this case
	 *
	 * @var string
	 */
	protected $_eventObject = 'object';
	
	/**
	 * Name of the resource model
	 *
	 * @var string
	 */
	protected $_resourceName;
	
	/**
	 * Resource model instance
	 *
	 * @var Mage_Core_Model_Mysql4_Abstract
	 */
	protected $_resource;
	
	/**
	 * Name of the resource collection model
	 *
	 * @var string
	 */
	protected $_resourceCollectionName;
	
	/**
	 * Model cache tag for clear cache in after save and after delete
	 *
	 * When you use true - all cache will be clean
	 *
	 * @var string || true
	 */
	protected $_cacheTag = false;
	
	/**
	 * Flag which can stop data saving after before save
	 * Can be used for next sequence: we check data in _beforeSave, if data are
	 * not valid - we can set this flag to false value and save process will be stopped
	 *
	 * @var bool
	 */
	protected $_dataSaveAllowed = true;
	
	/**
	 * Standard model initialization
	 *
	 * @param string $resourceModel
	 * @param string $idFieldName
	 * @return Evebit_Model_Abstract
	 */
	protected function _init($resourceModel) {
		$this->_setResourceModel($resourceModel);
	}
	
	/**
	 * Set resource names
	 *
	 * If collection name is ommited, resource name will be used with _collection appended
	 *
	 * @param string $resourceName
	 * @param string|null $resourceCollectionName
	 */
	protected function _setResourceModel($resourceName, $resourceCollectionName = null) {
		$this->_resourceName = $resourceName;
		if (is_null($resourceCollectionName)) {
			$resourceCollectionName = 'Evebit_Model_Mysql_Collection';
		}
		$this->_resourceCollectionName = $resourceCollectionName;
	}
	

	/**
	 * Get resource instance
	 *
	 * @return Mage_Core_Model_Mysql4_Abstract
	 */
	protected function _getResource() {
		if (!$this->_resourceName) {
			if (preg_match("|^(.+)_Model_Entity_(.+)$|", get_class($this), $match)) {
				$this->_setResourceModel($match[1] . "_Model_Resource_" . $match[2]);
			} else {
				throw new Exception('Resource is not set');
			}
		}
		
		return $this->getResourceSingleton($this->_resourceName);
	}
	
	/**
	 * Retrieve identifier field name for model
	 *
	 * @return string
	 */
	public function getIdFieldName() {
		if (!($fieldName = parent::getIdFieldName())) {
			$fieldName = $this->_getResource()->getIdFieldName();
			$this->setIdFieldName($fieldName);
		}
		return $fieldName;
	}
	
	/**
	 * Retrieve model object identifier
	 *
	 * @return mixed
	 */
	public function getId() {
		if ($fieldName = $this->getIdFieldName()) {
			return $this->_getData($fieldName);
		} else {
			return $this->_getData('id');
		}
	}
	
	/**
	 * Declare model object identifier value
	 *
	 * @param   mixed $id
	 * @return  Evebit_Model_Abstract
	 */
	public function setId($id) {
		if ($this->getIdFieldName()) {
			$this->setData($this->getIdFieldName(), $id);
		} else {
			$this->setData('id', $id);
		}
		return $this;
	}
	
	/**
	 * Retrieve model resource name
	 *
	 * @return string
	 */
	public function getResourceName() {
		return $this->_resourceName;
	}
	
	/**
	 * Get collection instance
	 *
	 * @return object
	 */
	public function getResourceCollection() {
		if (!$this->_resourceCollectionName) {
			if (preg_match("|^(.+)_Model_Entity_(.+)$|", get_class($this), $match)) {
				$this->_setResourceModel($match[1] . "_Model_Resource_" . $match[2]);
			} else {
				throw new Exception('Model collection resource name is not defined');
			}
		}
		return $this->getResourceModel($this->_resourceCollectionName, $this->_getResource());
	}
	
	/**
	 * @return Evebit_Model_Mysql_Collection
	 */
	public function getCollection() {
		return $this->getResourceCollection();
	}
	
	/**
	 * Load object data
	 *
	 * @param   integer $id
	 * @return  Evebit_Model_Abstract
	 */
	public function load($id, $field = null) {
		$this->_getResource()->load($this, $id, $field);
		
		$this->_afterLoad();
		$this->setOrigData();
		return $this;
	}
	
	/**
	 * Processing object after load data
	 *
	 * @return Evebit_Model_Abstract
	 */
	protected function _afterLoad() {
		return $this;
	}
	
	public function afterLoad() {
		$this->getResource()->afterLoad($this);
		$this->_afterLoad();
	}
	
	/**
	 * Save object data
	 *
	 * @return Evebit_Model_Abstract
	 */
	public function save() {
		$this->_getResource()->beginTransaction();
		try {
			$this->_beforeSave();
			if ($this->_dataSaveAllowed) {
				$this->_getResource()->save($this);
				$this->_afterSave();
			}
			$this->_getResource()->commit();
		} catch (Exception $e) {
			$this->_getResource()->rollBack();
			throw $e;
		}
		return $this;
	}
	
	/**
	 * Processing object before save data
	 *
	 * @return Evebit_Model_Abstract
	 */
	protected function _beforeSave() {
		return $this;
	}
	
	/**
	 * Processing object after save data
	 *
	 * @return Evebit_Model_Abstract
	 */
	protected function _afterSave() {
		if ($this->_cacheTag) {
			if ($this->_cacheTag === true) {
				$tags = array();
			} else {
				$tags = array($this->_cacheTag);
			}
			Mage::app()->cleanCache($tags);
		}
		return $this;
	}
	
	/**
	 * Delete object from database
	 *
	 * @return Evebit_Model_Abstract
	 */
	public function delete() {
		$this->_getResource()->beginTransaction();
		try {
			$this->_beforeDelete();
			$this->_getResource()->delete($this);
			$this->_afterDelete();
			
			$this->_getResource()->commit();
		} catch (Exception $e) {
			$this->_getResource()->rollBack();
			throw $e;
		}
		return $this;
	}
	
	/**
	 * Processing object before delete data
	 *
	 * @return Evebit_Model_Abstract
	 */
	protected function _beforeDelete() {
		return $this;
	}
	
	/**
	 * Processing object after delete data
	 *
	 * @return Evebit_Model_Abstract
	 */
	protected function _afterDelete() {
		if ($this->_cacheTag) {
			if ($this->_cacheTag === true) {
				$tags = array();
			} else {
				$tags = array($this->_cacheTag);
			}
		}
		return $this;
	}
	
	/**
	 * Retrieve model resource
	 *
	 * @return Evebit_Model_Mysql_Abstract
	 */
	public function getResource() {
		return $this->_getResource();
	}
	
	public function getEntityId() {
		return $this->getId();
	}
	
	private static $resources = array();
	
	public function getResourceSingleton($name) {
		if (isset(self::$resources[$name])) {
			return self::$resources[$name];
		}
		if (!class_exists($name)) {
			throw new Exception("Resource class '$name' not found");
		}
		self::$resources[$name] = new $name();
		return self::$resources[$name];
	}
	
	public function getResourceModel($name, $resource = null) {
		if (!class_exists($name)) {
			throw new Exception("Resource class '$name' not found");
		}
		$model = new $name(get_class($this), $resource);
		return $model;
	}
    
	public function getFormField($tableName){
		$fields = $this->getResource()->getReadConnection()->describeTable($tableName);
		$datas = null;
		foreach ($fields as $key => $field){
			$length = strpos($key, '_')?strpos($key, '_'):strlen($key);
			$prefix = substr($key, 0, $length);
			$data = null;
			$lable = substr($key, strpos($key, '_'));
			switch ($prefix){
				case 'radio':
					$data['type'] = 'radio';
					break;
				case 'select':
					$data['type'] = 'select';
					break;
				case 'password':
					$data['type'] = 'password';
					$data['label'] = 'Password';
					$datas[$key] = $data;
					$lable = 'confirm_password'; 
					$key = 'confirm_password';
					break;
				case 'id':
					$lable = null;
					$data['type'] = 'hidden';
					break;
				case 'upload':
					$data['type'] = 'file';
					break;
				default:
					$lable = $key;
					$data['type'] = 'input';	
			}
			$data['label'] = ucwords(trim(str_replace('_', ' ', $lable)));
			$datas[$key] = $data;
		}
		return $datas;
	}
}
